<?php
declare(strict_types=1);

namespace app\common\business;

use app\platform\model\RoleMenuRelation as RoleMenuRelationModel;
use Exception;
use app\common\model\Menu as MenuModel;
use app\common\model\CommonBase as CommonBaseModel;

class Menu extends CommonBase
{
    private $_menuObj = null;
    private const _LEVEL_PREFIX       = "├─ ";
    private const _LAST_LEVEL_PREFIX  = "└─ ";
    private const _FIRST_LEVEL_PREFIX = "│　";

    public function __construct()
    {
        $this->_menuObj = new MenuModel();
    }

    public function getAllMenu(array $where = []): array
    {
        $res   = [];
        $count = 0;
        try {
            $menus = $this->_menuObj->getAllMenu($where)->toArray();
            $count = count($menus);


            $res = $this->_getCurCategoryChildren($menus, 0);

        } catch (\Exception $e) {
            logErr('读取所有菜单失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return ['rows' => $this->_wrapTitle($res), 'count' => $count];
    }

    public function getMenuList(int $page = 1, int $limit = 10, array $where = []): array
    {
        $rows  = [];
        $count = 0;
        try {
            $rows  = $this->_menuObj->getMenuList($page, $limit, $where);
            $count = $this->_menuObj->getMenuCount($where);
        } catch (\Exception $e) {
            logErr('读取菜单列表失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return ['rows' => $rows ? $rows->toArray() : [], 'count' => $count];
    }

    public function addMenu(array $data): array
    {
        try {
            if (!isset($data['business_type']) && $data['pid'] != 0) {
                $parentMenu            = $this->_menuObj->findMenuById($data['pid']);
                $data['business_type'] = $parentMenu['business_type'];
            }

            return [self::_RESULT => $this->_menuObj->addMenu($data), self::_MESSAGE => self::_ADD_SUCCESS_MESSAGE];
        } catch (\Exception $e) {
            logErr('添加菜单失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return [self::_RESULT => false, self::_MESSAGE => self::_SYSTEM_ERROR_MESSAGE];
    }

    public function findMenuById(int $id): array
    {
        $menu = null;
        try {
            $menu = $this->_menuObj->findMenuById($id);
        } catch (\Exception $e) {
            logErr('通过主键读取菜单详细信息失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        if (empty($menu)) {
            return [];
        }

        return $menu->toArray();
    }

    public function updateMenu(int $id, array $data): array
    {
        try {
            return [self::_RESULT => $this->_menuObj->updateMenu($id, $data), self::_MESSAGE => self::_UPDATE_SUCCESS_MESSAGE];
        } catch (\Exception $e) {
            logErr('通过主键更新菜单信息失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return [self::_RESULT => false, self::_MESSAGE => self::_SYSTEM_ERROR_MESSAGE];
    }

    public function deleteMenu(int $id): array
    {
        try {
            $children = $this->_menuObj->findMenuByPid($id);
            if (!empty($children->toArray())) {
                return [self::_RESULT => false, self::_MESSAGE => self::_DELETE_MENU_HAS_CHILD_ERROR];
            }

            $res = $this->_menuObj->deleteMenu($id);
            return [self::_RESULT => $res, self::_MESSAGE => self::_DELETE_SUCCESS_MESSAGE];
        } catch (\Exception $e) {
            logErr('通过主键删除菜单失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return [self::_RESULT => false, self::_MESSAGE => self::_SYSTEM_ERROR_MESSAGE];
    }

    public function batchMenuSort(array $data): array
    {
        try {
            return [self::_RESULT => $this->_menuObj->batchMenuSort($data), self::_MESSAGE => self::_SORT_SUCCESS_MESSAGE];
        } catch (\Exception $e) {
            logErr('通过主键排序菜单失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return [self::_RESULT => false, self::_MESSAGE => self::_SYSTEM_ERROR_MESSAGE];
    }

    public function getRolePermissionMenuTree(array $roleIds): array
    {
        try {
            $permissionMenuIds = [];
            $RoleMenuObj       = new RoleMenuRelationModel();
            $roleMenuRelations = $RoleMenuObj->getAllRoleMenuRelation([['role_id', 'in', $roleIds]])->toArray();
            foreach ($roleMenuRelations as $roleMenuRelation) {
                $permissionMenuIds[] = $roleMenuRelation['menu_id'];
            }
            $menus = $this->_menuObj->getAllMenu()->toArray();
            return $this->_getRolePermissionMenuTree($menus, 0, $permissionMenuIds);
        } catch (Exception $e) {
            logErr('通过角色id获取有权限的菜单失败(包过按钮)', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return [];
    }

    public function getPlatformPermissionMenus(array $roleIds): array
    {
        $menuTree      = $this->_getLoginRolePermissionMenus($roleIds);
        $platformMenus = [];
        foreach ($menuTree as $v) {
            if ($v['business_type'] == CommonBaseModel::PLATFORM_MENU) {
                $platformMenus = $v['children'] ?? [];
            }
        }

        return $platformMenus;
    }

    public function getBackendPermissionMenus(array $roleIds): array
    {
        $menuTree      = $this->_getLoginRolePermissionMenus($roleIds);
        $platformMenus = [];
        foreach ($menuTree as $v) {
            if ($v['business_type'] == CommonBaseModel::BACKEND_MENU) {
                $platformMenus = $v['children'] ?? [];
            }
        }

        return $platformMenus;
    }

    public function getLoginRolPermissionActions(array $roleIds): array
    {
        try {
            $permissionMenuIds = [];
            $RoleMenuObj       = new RoleMenuRelationModel();
            $roleMenuRelations = $RoleMenuObj->getAllRoleMenuRelation([['role_id', 'in', $roleIds]])->toArray();
            foreach ($roleMenuRelations as $roleMenuRelation) {
                $permissionMenuIds[] = $roleMenuRelation['menu_id'];
            }
            $menus       = $this->_menuObj->getAllMenu()->toArray();
            $actions     = $this->_getLoginRolPermissionActions($menus, 0, $permissionMenuIds);
            $menuCodes   = [];
            $actionPaths = [];
            foreach ($actions as $action) {
                $menuCodes[]   = $action["menu_code"];
                if (!empty($action["api_path"])) {
                    $actionPaths[] = $action["api_path"];
                }
                if (!empty($action["path"])) {
                    $actionPaths[] = $action["path"];
                }
            }
            return ['menuCodes' => $menuCodes, 'actionPaths' => $actionPaths];
        } catch (Exception $e) {
            logErr('通过角色id获取有权限的菜单失败(排除按钮)', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return ['menuCodes' => [], 'actionPaths' => []];
    }

    private function _getLoginRolPermissionActions(array $menus, int $pid, array $permissionMenuIds): array
    {
        $res = [];
        foreach ($menus as $menu) {
            if (!in_array($menu['id'], $permissionMenuIds)) {
                continue;
            }

            // if ($menu['menu_type'] == CommonBaseModel::IS_MENU) {
            //     continue;
            // }

            if ($menu['status'] == CommonBaseModel::IS_DISABLE_STATUS) {
                continue;
            }

            $res             [] = [
                'id'        => $menu['id'],
                'pid'       => $menu['pid'],
                'title'     => $menu['menu_name'],
                'api_path'  => $menu['api_path'],
                'path'      => $menu['path'],
                'menu_code' => $menu['menu_code'],
            ];
        }

        return $res;
    }

    private function _getLoginRolePermissionMenus(array $roleIds): array
    {
        try {
            $permissionMenuIds = [];
            $RoleMenuObj       = new RoleMenuRelationModel();
            $roleMenuRelations = $RoleMenuObj->getAllRoleMenuRelation([['role_id', 'in', $roleIds]])->toArray();
            foreach ($roleMenuRelations as $roleMenuRelation) {
                $permissionMenuIds[] = $roleMenuRelation['menu_id'];
            }
            $menus = $this->_menuObj->getAllMenu()->toArray();
            return $this->_getLoginRolePermissionMenuTree($menus, 0, $permissionMenuIds);
        } catch (Exception $e) {
            logErr('通过角色id获取有权限的菜单树失败', sprintf('method:%s,err:%s', __METHOD__, $e->getMessage()));
        }

        return [];
    }

    private function _getLoginRolePermissionMenuTree(array $menus, int $pid, array $permissionMenuIds): array
    {
        $res = [];
        foreach ($menus as $menu) {
            if ($menu['pid'] == $pid) {
                if (!in_array($menu['id'], $permissionMenuIds)) {
                    continue;
                }

                if ($menu['menu_type'] == CommonBaseModel::IS_BUTTON) {
                    continue;
                }

                if ($menu['status'] == CommonBaseModel::IS_DISABLE_STATUS) {
                    continue;
                }

                $one             = [
                    'id'            => $menu['id'],
                    'pid'           => $menu['pid'],
                    'title'         => $menu['menu_name'],
                    'api_path'      => $menu['api_path'],
                    'path'          => $menu['path'],
                    'icon_layui'    => $menu['icon_layui'],
                    'business_type' => $menu['business_type'],
                ];
                $children        = $this->_getLoginRolePermissionMenuTree($menus, $menu['id'], $permissionMenuIds);
                $one['children'] = $children;

                $res [] = $one;
            }
        }
        return $res;
    }

    private function _getRolePermissionMenuTree(array $menus, int $pid, array $permissionMenuIds): array
    {
        $res = [];
        foreach ($menus as $menu) {
            if ($menu['pid'] == $pid) {
                $one             = [
                    'id'      => $menu['id'],
                    'pid'     => $menu['pid'],
                    'title'   => $menu['menu_name'],
                    'checked' => false, // 选中状态
                    'spread'  => true, // 展开状态
                ];
                $children        = $this->_getRolePermissionMenuTree($menus, $menu['id'], $permissionMenuIds);
                $one['children'] = $children;

                // 有children的节点，不处理选中状态
                // 因为父节点勾选后，所有的子节点会自动选中
                if (count($permissionMenuIds) && !count($children)) {
                    $one['checked'] = in_array($menu['id'], $permissionMenuIds);
                }

                $res [] = $one;
            }
        }
        return $res;
    }

    private function _getCurCategoryChildren(array $menus, int $pid): array
    {
        $res = [];
        foreach ($menus as $menu) {
            if ($menu['pid'] == $pid) {
                $res[] = $menu;
                $res   = array_merge($res, $this->_getCurCategoryChildren($menus, $menu['id']));
            }
        }

        return $res;
    }

    private function _wrapTitle(array $menus): array
    {
        $menuLen   = count($menus);
        $num       = 1;
        $prefixMap = [1];
        foreach ($menus as $k => $v) {
            if ($k > 0) {
                if ($menus[$k - 1]['pid'] != $v['pid']) {
                    $num++;
                }
            }

            if (isset($prefixMap[$v['pid']])) {
                $num = $prefixMap[$v['pid']];
            }

            $prefixMap[$v['pid']] = $num;

            $repeatFlag = '';
            for ($i = 0; $i < $num - 1; $i++) {
                if ($i == $num - 2) {
                    if ($k + 1 < $menuLen && $v['pid'] <= $menus[$k + 1]['pid']) {
                        $repeatFlag .= self::_LEVEL_PREFIX;
                    } else {
                        $repeatFlag .= self::_LAST_LEVEL_PREFIX;
                    }
                } else {
                    $repeatFlag .= self::_FIRST_LEVEL_PREFIX;
                }
            }

            $warpTitle                   = $repeatFlag . $v['menu_name'];
            $menus[$k]['menu_name']      = $warpTitle;
            $menus[$k]['menu_type_name'] = $v['menu_type'] == CommonBaseModel::IS_MENU ? '菜单' : '按钮';
        }

        return $menus;
    }

}
